﻿// Copyright (c) 2011 Blue Onion Software, All rights reserved
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
using BlueOnionSoftware.Bloget;
using NUnit.Framework;

namespace BlogetTests
{
    [TestFixture]
    [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
    public class FileUtilitiesTests
    {
        private string tempFile;
        private string writeFile;
        private string writeFileBackup;

        [TestFixtureSetUp]
        public void Setup()
        {
            tempFile = Path.GetTempFileName();
            writeFile = Path.GetTempFileName();
            writeFileBackup = writeFile + ".bak";
        }

        [TestFixtureTearDown]
        public void TearDown()
        {
            if (File.Exists(tempFile))
            {
                File.Delete(tempFile);
            }

            if (File.Exists(writeFile))
            {
                File.Delete(writeFile);
            }

            if (File.Exists(writeFileBackup))
            {
                File.Delete(writeFileBackup);
            }
        }

        [Test]
        public void OpenWrite()
        {
            using (var stream = FileUtilities.OpenCreate(tempFile))
            {
                Assert.IsTrue(stream.CanWrite);
                Assert.AreEqual(0, stream.Position);
            }
        }

        [Test]
        public void OpenRead()
        {
            using (var stream = FileUtilities.OpenRead(tempFile))
            {
                Assert.IsTrue(stream.CanRead);
                Assert.IsFalse(stream.CanWrite);
            }
        }

        [Test]
        public void OpenAppend()
        {
            using (var stream = FileUtilities.OpenCreate(tempFile))
            {
                stream.WriteByte(0x00);
            }

            using (var stream = FileUtilities.OpenAppend(tempFile))
            {
                Assert.AreEqual(1, stream.Position);
            }
        }

        [Test]
        [ExpectedException(typeof (IOException))]
        public void TestWriteLock()
        {
            using (var stream = FileUtilities.OpenCreate(tempFile))
            {
                var stream2 = FileUtilities.OpenRead(tempFile);
            }
        }

        [Test]
        [ExpectedException(typeof (IOException))]
        public void TestReadWriteLock()
        {
            using (var stream = FileUtilities.OpenRead(tempFile))
            {
                var stream2 = FileUtilities.OpenCreate(tempFile);
            }
        }

        [Test]
        [ExpectedException(typeof (IOException))]
        public void TestReadAppendLock()
        {
            using (var stream = FileUtilities.OpenRead(tempFile))
            {
                var stream2 = FileUtilities.OpenAppend(tempFile);
            }
        }

        [Test]
        [ExpectedException(typeof (IOException))]
        public void TestAppendLock()
        {
            using (var stream = FileUtilities.OpenAppend(tempFile))
            {
                var stream2 = FileUtilities.OpenRead(tempFile);
            }
        }

        [Test]
        [ExpectedException(typeof (FileNotFoundException))]
        public void TestReadFileNotFound()
        {
            var nonexistentFile = tempFile + "xyz";
            Assert.IsFalse(File.Exists(nonexistentFile));

            using (var stream = FileUtilities.OpenRead(nonexistentFile))
            {
                Assert.Fail();
            }
        }

        [Test]
        [ExpectedException(typeof (DirectoryNotFoundException))]
        public void TestDirectoryNotFound()
        {
            var nonexistentDirectory = Path.Combine(tempFile, "xyz");

            using (var stream = FileUtilities.OpenRead(nonexistentDirectory))
            {
                Assert.Fail();
            }
        }

        [Test]
        [ExpectedException(typeof (PathTooLongException))]
        public void TestPathTooLong()
        {
            var longName = new StringBuilder(tempFile);
            longName.Append('x', 5000);

            using (var stream = FileUtilities.OpenRead(longName.ToString()))
            {
                Assert.Fail();
            }
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void WriteFileFileNameNull()
        {
            FileUtilities.WriteFile(null, new MemoryStream());
        }

        [Test]
        [ExpectedException(typeof (ArgumentException))]
        public void WriteFileFileNameEmpty()
        {
            FileUtilities.WriteFile(" ", new MemoryStream());
        }

        [Test]
        [ExpectedException(typeof (ArgumentNullException))]
        public void WriteFileByteBufferNull()
        {
            FileUtilities.WriteFile(tempFile, null);
        }

        [Test]
        public void WriteFileWriteLock()
        {
            using (var stream = FileUtilities.OpenAppend(writeFile))
            {
                try
                {
                    Stream memoryStream = new MemoryStream(new byte[] {0x05});
                    FileUtilities.WriteFile(writeFile, memoryStream);
                    Assert.Fail("WriteFile was successful, lock failed");
                }

                catch (Exception ex)
                {
                    Assert.IsInstanceOf<IOException>(ex);
                }
            }
        }

        [Test]
        public void WriteFile()
        {
            Stream memoryStream = new MemoryStream(new byte[] {0x01, 0x02});
            FileUtilities.WriteFile(writeFile, memoryStream);
            Assert.IsTrue(File.Exists(writeFileBackup));

            using (var fileStream = FileUtilities.OpenRead(writeFile))
            {
                Assert.AreEqual(0x01, fileStream.ReadByte());
                Assert.AreEqual(0x02, fileStream.ReadByte());
                Assert.AreEqual(-1, fileStream.ReadByte());
            }
        }
    }
}